#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QProcess>
#include <QApplication>
#include <QTranslator>

#ifndef Q_OS_WIN
#include <fcntl.h>
#include <unistd.h>
#endif

#include "ui_mainwindow.h"
#include "sourcetype.h"

#define Elf32_Addr      unsigned int
#define Elf32_Half      unsigned short
#define Elf32_Off       unsigned int
#define Elf32_Sword     int
#define Elf32_Word      unsigned int
#define uchar           unsigned char

#define    EI_NIDENT    16

#define PIPE_NAME       "GUIDE_FIFO"
#define FILE_MAXLENGTH  1024

class MainWindow;

class QAction;
class QActionGroup;
class QMenu;
class EditorTabWidget;
class FileBrowser;
class FindWidget;
class HelpWidget;
static const int maxRecentsFiles = 10;

class GDBMI;
class GDBMIDefaultClient;
class GDBMIExecClient;
class GDBMIStackClient;
class GDBMIVariableClient;
class GDBMIMemoryClient;
class QListWidgetItem;
class MEventHandler;


typedef    struct{
    unsigned    char    e_ident[EI_NIDENT];
    Elf32_Half    e_type;
    Elf32_Half    e_machine;
    Elf32_Word    e_version;
    Elf32_Addr    e_entry;
    Elf32_Off    e_phoff;
    Elf32_Off    e_shoff;
    Elf32_Word    e_flags;
    Elf32_Half    e_ehsize;
    Elf32_Half    e_phentsize;
    Elf32_Half    e_phnum;
    Elf32_Half    e_shentsize;
    Elf32_Half    e_shnum;
    Elf32_Half    e_shstrndx;
}Elf32_Ehdr;

typedef struct{ 
    Elf32_Word sh_name;
    Elf32_Word sh_type;
    Elf32_Word sh_flags;
    Elf32_Addr sh_addr;
    Elf32_Off sh_offset;
    Elf32_Word sh_size;
    Elf32_Word sh_link;
    Elf32_Word sh_info;
    Elf32_Word sh_addralign;
    Elf32_Word sh_entsize;
} Elf32_Shdr;

class MainWindow : public QMainWindow, public Ui::MainWindow
{
    Q_OBJECT
public:
    MainWindow();
    virtual ~MainWindow ();

    void onTargetStop (int line,int bkptno);
    void onTargetStop (QString fullfilename,int line);
    void onTargetStop (QString msg);
    void onTargetStop ();
    bool doOpenFile(const QString &file);
    inline EditorTabWidget *getEditorTab() {
        return m_editorTab;
    }
    //bool isInVarList(QString str);

protected:
    void closeEvent(QCloseEvent *event);
    void keyPressEvent(QKeyEvent *event);
#ifdef    Q_OS_WIN
    bool winEvent(MSG *msg, long *result);
#endif
    void dragEnterEvent ( QDragEnterEvent * event );
    void dropEvent( QDropEvent * event );

public slots:
    void slotDebugFinished();
    void setDebugMessage (QString message, int level);
    void stopDebug ();
    void toConditional(QString file, int line, QString condition);
    void slotaddVarWatch(QString str);
    void slotToggleBreakpoint(QString file, int line);

private slots:
    void newFile();
    void openFile();
    bool save();
    bool saveAs();
    void about();
    void slotHelp();
    void slotOpenRecentFile();

    void slotSearch();
    void slotSearchNext();
    void slotSearchPrevious();
    void slotGoto();
    void slotGotoBrace();
    void slotFindRequest (QString expr, bool re, bool cs, bool whole, bool forward);
    void slotReplaceRequest(QString srcexpr,QString desexpr,bool re, bool cs, bool whole, bool replaceAll);
    void slotManageBreakpoints();
    //void slotTable();
    void slotSettings();
    void slotApplySettings();

    void slotFileBrowserDblClickFile(QString fname);

    void slotCloseFile();
    void slotCloseAllFiles();
    void slotCloseOtherFiles();

    /* For editor tabwidget signals */
    void slotFileClosed(int index);

    void slotCompile();
    void slotStopCompile();
    void slotExecute();
    void slotStopExecute();
    void slotStopExecute(QProcess::ProcessState newstate);
    void slotEndBuild(bool succ);
    void slotRunAfterBuild(bool succ, QString srcfile);

    void slotBuildLogClicked(QString fn, int line);
    void slotExecuteOutput(QString msg, bool bStdErr);
    void slotExecuteFinished(bool started, int exitCode, QProcess::ExitStatus exitStatus);

    void slotDebug();
    void slotSetParams();
    void slotPauseResume();
    void slotOnPause();
    void slotOnContinue();
    void slotToggleBreakpoint(QString condition = QString());
    void slotStepOver();
    void slotRuntoCursor();
    void slotStepInto();
    void slotStepOut();
    void slotDebugAfterBuild(bool succ, QString srcfile);

    void slotSearchHelpFile();

    void slotAddWatch(QString str = "");
    void slotRemoveWatch();

    void slotShowMemory();

    void slotItemDoubleClicked (QListWidgetItem * item);
    //void slotStackListChanged(QString fullfilename,QString funcname,int curline,int stackdepth);
    void slotLanguageChinese();
    void slotLanguageEnglish();

    void resetExternTool();

#ifndef Q_OS_WIN
    void slotlinuxMsg();
#endif

private:
    enum RunState {EditMode = 0, CompileMode, ExecMode, DebugMode};

    void installTranslators();
    void createActions();
    void reCreateStatusTips();
    void createMenus();
    void createToolBars();
    void createStatusBar();
    void connectSignals();

    //bool doOpenFile(const QString &file);
    void loadRecentFiles();
    void setRecentFile(const QString & file);

    void readSettings();
    void writeSettings();

    bool maybeSave();
    QString strippedName(const QString &fullFileName);
    bool getCurrentFileNames(QString &fullname, QString &dirname, QString &filename, QString &exename);
    bool getCompileCmd(QString &cmdline, QString srcname, QString targetname);
    bool getSourceType(SourceType &type, QString srcname);

    void doCompile(bool run = false, bool debug = false);
    void doExecute(QString srcfile);
    void doDebug(QString srcfile);
    void initCurrentBreakpoints();

    /* return 2, exec file does not exist.
     * return 1, src file is newer than exe file.
     * return 0, src file is at same time with exe file.
     * return -1, src file is older than exe file.
     */
    int compareExecutalbAndSource(QString dirName, QString srcName, QString exeName);
    void appendToExecuteOutput(QString message, bool Stderr = false);

    void changeRunState (RunState state);

    QString gdbstrToUnicode(QString src);
    /*
    QString m_varList;
    bool getVarList(QString targetFullName);
    */

    /*

    */
    void setButtonState(int flag);

    FindWidget *m_finder;
    QLineEdit *m_searchKey;
    QAction *m_searchAction;

    QString m_targetOutput;
    QAction *m_actionsRecentsFiles[maxRecentsFiles];
    QTranslator m_myTranslator;
    QTranslator m_qtTranslator;

    RunState m_state;
    bool stopAtMain;
    int lastStepLine; //use to record the last stepline.

signals:
    void stopBuild();
    void stopExecute();

    void buildFinished(bool succ, QString srcFilename);
    void pauseDebug();
    void watchVariables(QStringList);
    void breakpoint(QString, unsigned int, bool);
    //void debugCommand(QString);
    void continueDebug();

private:
    bool userPrompt ();

private:
    GDBMI                * m_debugger;
    GDBMIDefaultClient    * m_defaultClient;
    GDBMIExecClient        * m_execClient;
    GDBMIStackClient    * m_stackClient;
    GDBMIVariableClient    * m_variableClient;
    GDBMIMemoryClient   * m_memoryClient;
    MEventHandler        * m_eventHandler;
    QProcess            * runProcess;

    uint                m_lastModified;
    QString                m_curDirectory;
    QTimer              * m_timer;

    QMap<QString, QString>    m_srcExeMap;
public:
    QString                m_activeFileName;
};

#endif
